package design_pattern.Volatile;

/**
 * @Author: 蔡翔
 * @Date: 2019/10/25 13:35
 * @Version 1.0
 *
 *  volatile使共享变量 保持多线程安全。 但是线程一多还是有问题（原因是cpu有自己的cache变量操作也都是在这个cache里面的，多核（cpu）情况下 cpu的cache是不共享的。）。
 *  volatile 修饰的变量，当这个变量发生改变的时候会重新写入内存的。其他线程取这个变量的时候也是从主内存取得。对一个变量的写操作优于变量的读操作。
 *  volatile并不能保证原子性，但是能够保证两个特点：1.内存可见性（就是要拿这个变量的时候会去主内存拿）。2.程序执行有序性。
 *  这就是缓存不一致的问题。
 */
public class VolatileTest {
    //INIT_VALUE 是共享数据。虽然他没有加锁，但是用了volatile，就做到了类似于线程安全的一个东西。
    //private volatile static int INIT_VALUE = 0;
    private static volatile int INIT_VALUE = 0;

    private final static int MAX_LIMIT = 50;

    public static void main(String[] args) {
        new Thread(()->{
            //不加volatile造成的问题：外接明明对INIT_VALUE改变了，但是这个线程感知不到。
            // java 给我们自作多情的优化，因为这个线程没有对INIT_VALUE进行写操作。java就默认这个INIT_VALUE 不需要更新主内存，取INIT_VALUE得时候不需要去主内存拿了，它就在cpu的cache里面那。
            //如果把INIT_VALUE的volatile去掉，那么另外一个线程是感知不到INIT_VALUE发生的变化的（所以这就线程不安全）
            // 这里的INIT_VALUE只会去主内存那里拿一份，然后始终放在高速缓存中，不管怎么读都从这高速缓存取。不和外接交互了。
            int localValue = INIT_VALUE;
            // INIT_VALUE加入volatile后 这个线程中的cache value就失效了，就被迫去主内存 读数据。
            while (localValue<MAX_LIMIT){
                if(localValue!=INIT_VALUE){
                    System.out.println("The value updated to "+INIT_VALUE);
                    // 这里重新复制一下，下次就不成立了。
                    localValue = INIT_VALUE;
                }
            }
        },"READY").start();

        new Thread(()->{
            int localValue2 = INIT_VALUE;
            while (INIT_VALUE<MAX_LIMIT){
                localValue2++;
                System.out.println("Update the value to "+ localValue2);
                INIT_VALUE = localValue2;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"UPDATE").start();
    }
}
